using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pumpkin.Utils
{
    public static class CollectionUtils
    {
        public static T First<T>(this IList<T> list)
        {
            return list[0];
        }

        public static T Last<T>(this IList<T> list)
        {
            return list[list.Count - 1];
        }
        public static bool IsCorrectIndex<T>(this IList<T> list, int index)
        {
            return index >= 0 && index < list.Count;
        }

        public static T GetOrDefault<T>(this IList<T> list, int index, T t = default(T))
        {
            return list.IsCorrectIndex(index) ? list[index] : t;
        }

        public static T GetOrDefault<K, T>(this IDictionary<K, T> dict, K key, T t = default(T))
        {
            if (dict.TryGetValue(key, out T v))
            {
                return v;
            }
            return t;
        }

        public static bool IsEmpty<T>(this ICollection<T> collection)
        {
            return collection.Count == 0;
        }

        public static bool IsEmpty<T>(this T collection) where T : ICollection
        {
            return collection.Count == 0;
        }

        public static bool IsEmpty<T>(this IEnumerable<T> list)
        {
            return !list.Any();
        }

        public static int RemoveAll<K, T>(this IDictionary<K, T> dict, Predicate<KeyValuePair<K, T>> match)
        {
            List<K> removeKeys = new List<K>();
            foreach (var pair in dict)
            {
                if (match(pair))
                {
                    removeKeys.Add(pair.Key);
                }
            }
            foreach (var key in removeKeys)
            {
                dict.Remove(key);
            }
            return removeKeys.Count;
        }

        public static void AddAt<T>(this List<T> list, int index, T v)
        {
            if (index < list.Count)
            {
                list[index] = v;
            }
            else
            {
                int count = index - list.Count;
                for (int i = 0; i < count; ++i)
                {
                    list.Add(default(T));
                }
                list.Add(v);
            }
        }

        public static int AddFixed<T>(this List<T> list, T t, int maxCount)
        {
            list.Add(t);
            if (list.Count > maxCount)
            {
                int count = list.Count - maxCount;
                list.RemoveRange(0, count);
                return count;
            }
            return 0;
        }

        public static bool RemoveFirst<T>(this List<T> list, Predicate<T> macth)
        {
            T _;
            return list.RemoveFirst(macth, out _);
        }

        public static bool RemoveFirst<T>(this List<T> list, Predicate<T> macth, out T item)
        {
            bool success = false;
            item = default(T);

            int index = list.FindIndex(macth);
            if (index != -1)
            {
                item = list[index];
                list.RemoveAt(index);
                success = true;
            }

            return success;
        }

        public static List<T> Distinct<T>(this IEnumerable<T> list, Func<T, T, bool> comparer)
        {
            List<T> set = new List<T>();
            foreach (var i in list)
            {
                if (!set.Exists(e => comparer(e, i)))
                {
                    set.Add(i);
                }
            }
            return set;
        }
    }
}